import UIKit
import Foundation

//定义和调用异步 你可以在它的声明中的参数列表后边加上 async 关键字
func listPhoto(inGalllery name:String) async -> [String] {
    try? await Task.sleep(nanoseconds: 2 * 1_000_000) //两秒
    return ["IMAGE01","IMAGE02","IMAGE03"]
}

func showPhoto(name:String) async {
    
}

func downloadPhoto(_ name:String) async {
    
}

await listPhoto(inGalllery: "ddd")
await showPhoto(name:"bb")
print("end")
//因为 listPhotos(inGallery:) 和 downloadPhoto(named:) 都需要发起网络请求，需要花费较长的时间完成。给这两个函数在返回箭头前加上 async 可以将它们定义为异步函数，从而使得这部分代码在等待图片的时候让程序的其他部分继续运

//let handle = FileHandle.standardInput
//for try async line in handle.bytes.lines {
//    print(line)
//}

//并行的调用异步方法 在异步代码执行的过程中，调用方需要等待异步代码执行完后才能继续执行下一行代码。比如，当你想从图库中拉取前三张图片，可以像下面这样，等三次调用完后再执行 downloadPhoto(named:) 函数：

func show(_ photos:[String]) {
    
}
let firstPhoto = await downloadPhoto("aaa")
let secondPhoto = await downloadPhoto("bbb")
let thirdPhoto = await downloadPhoto( "ccc")
let photos = [firstPhoto, secondPhoto, thirdPhoto]
show(photos)

//这种方式有一个非常严重的缺陷：虽然下载过程是异步的，并且在等待过程中可以执行其他任务，但每次只能执行一个 downloadPhoto(named:)。每一张图片只能在上一张图片下载结束了才开始下载。然而，并没有必要让这些操作等待，每张图片可以独立甚至同时下载。
async let firstPhoto1 =  downloadPhoto("aaa")
async let secondPhoto1 =  downloadPhoto("bbb")
async let thirdPhoto1 =  downloadPhoto("ccc")
let photoss = await [firstPhoto1, secondPhoto1, thirdPhoto1]
show(photoss)
//在上面的例子中，三次调用 downloadPhoto(named:) 都不需要等待前一次调用结束。如果系统有足够的资源，这三次调用甚至都可以同时执行。这三次调用都没有没标记为 await，因为代码不需要被挂起等待函数的结果。程序会继续执行直到 photos 被定义，与上面不同的是，在这个时间点由于程序需要上面几次异步调用的结果，所以你需要添加 await 关键字来挂起当前代码的执行直到所有图片下载完成。

//总结： 
//1.代码中接下来的几行需要依赖异步函数的结果时，需要使用 await 来调用异步函数。这样产生的结果是有序的。
//2.短时间内并不需要异步函数的结果时，需要使用 async-let 来调用异步函数。这样产生的任务是并发的。
//3.await 和 async-let 都允许其他任务在他们被挂起的时候执行。
//4.在两种情况下，都需要用 await 标记可能的悬点，以表明代码在这些点在需要的情况下会被挂起，直到异步函数执行结束。

//任务和任务组

await withTaskGroup(of: Data.self) { taskGroup in
    let photoNames = await listPhoto(inGalllery: "Summer Vacation")
        for name in photoNames {
//            taskGroup.async { await downloadPhoto(named: name)
//            }
        }
}


//非结构化并发

 func add(_ pho:String, toGalleryNamed name: String) async {
    
}
let newPhoto = ""
let handle = Task {
    return await add(newPhoto, toGalleryNamed: "Spring Adventures")
}

let result = await handle.value
let canceld = Task.isCancelled
if canceld {
    
}

//Actors actor 在同一时间只允许一个任务访问它的可变状态，这使得多个任务中的代码与一个 actor 交互时更加安全

actor TemperatureLogger {
    let lebel: String
    var measurements: [Int]
    private(set) var max: Int
    init(lebel: String, measurement:Int ) {
        self.lebel = lebel
        self.max = measurement
    }
}

//你可以用 actor 关键字引入一个 actor，后边的花括号中是它的定义。TemperatureLogger 中有外部能访问到的属性，并且限制 max 变量，所以只能在 actor 内部修改最大值。
let logger = TemperatureLogger(lebel: "outdoors", measurement: 25)
await logger.max


//当你访问 actor 中的属性或方法时，需要使用 await 来标记潜在的悬点 在		这个例子中，访问 logger.max 是一个可能的悬点。因为 actor 在同一时间只允许一个任务访问它的可变状态，如果别的任务正在与 logger 交互，上面这段代码将会在等待访问属性的时候被挂起。

//不添加 await 关键字的情况下访问 logger.max 会失败，因为 actor 的属性是它隔离的本地状态的一部分。Swift 可以保证只有 actor 内部的代码可以访问 actor 的内部状态。这个保证也被称为 actor isolation。
